package com.niiwoo.civet.trade.service.local.loan.submit;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.fastjson.JSON;
import com.niiwoo.activity.event.enums.UsableCreditChangeTypeEventEnum;
import com.niiwoo.activity.stage.dto.request.inviteBuddy.ProjectPublishEventDTO;
import com.niiwoo.activity.stage.dto.request.prize.ActivityPrizeResetStatusReqDTO;
import com.niiwoo.activity.stage.dto.request.prize.ActivityPrizeStatusReqDTO;
import com.niiwoo.activity.stage.enums.prize.UserPrizeSuitProjectTypeEnum;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.base.enums.DeadlineUnitEnum;
import com.niiwoo.civet.base.utils.ProjectInfoUtil;
import com.niiwoo.civet.trade.constant.MqConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.AuditAdditionalInfoMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectCreditAmountMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectLoanDeviceInfoMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectRateMapperExt;
import com.niiwoo.civet.trade.dto.BorrowPrizeOccupyDTO;
import com.niiwoo.civet.trade.dto.DataBackflowStatusAndDetailsDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDynamicDTO;
import com.niiwoo.civet.trade.dto.request.ProjectFlowRequestDTO;
import com.niiwoo.civet.trade.dto.request.databackflow.ProjectStatusChangeBackFlowRequestDTO;
import com.niiwoo.civet.trade.dto.request.loan.*;
import com.niiwoo.civet.trade.dto.response.loan.FadadaWithholdContractSignResponseDTO;
import com.niiwoo.civet.trade.dto.response.loan.LoanConfigResDTO;
import com.niiwoo.civet.trade.dto.response.loan.LoanSubmitCommResDTO;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.service.local.activity.ActivityEventService;
import com.niiwoo.civet.trade.service.local.databackflow.DataBackflowStatusService;
import com.niiwoo.civet.trade.service.local.flowexecute.ProjectFlowExecuteService;
import com.niiwoo.civet.trade.service.local.loan.SpeedLoanService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.civet.user.dto.request.DataStatusRequestDTO;
import com.niiwoo.civet.user.dto.response.DataStatusResponseDTO;
import com.niiwoo.civet.user.dto.response.UserAuthorizationInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserBasicInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserIdentityInfoResponseDTO;
import com.niiwoo.civet.user.enums.UserDataStatusEnum;
import com.niiwoo.civet.user.enums.UserDataTypeEnum;
import com.niiwoo.civet.user.enums.UserIdentityEnum;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.Duration;
import org.joda.time.LocalDate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;

/**
 * @Author: wuke
 * @Description:
 * @Date: Created in 16:57 2018/4/13
 */
@Slf4j
public abstract class AbstractLoanSubmitService<I extends LoanSubmitReqDTO,O extends LoanSubmitCommResDTO> extends AbstractLoanCheckService<I ,O> {
    @Autowired
    protected RedissonClient redissonClient;
    @Autowired
    protected SpeedLoanService loanLocalService;
    @Autowired
    protected ProjectLocalService projectLocalService;
    @Autowired
    protected DataBackflowStatusService dataBackflowStatusService;
    @Autowired
    protected ProjectFlowExecuteService projectFlowExecuteService;
    @Autowired
    private ActivityEventService activityEventService;
    @Autowired
    protected ProjectLoanDeviceInfoMapperExt projectLoanDeviceInfoMapper;
    @Autowired
    protected ProjectRateMapperExt projectRateMapper;
    @Autowired
    private AuditAdditionalInfoMapperExt auditAdditionalInfoMapper;
    @Autowired
    protected ProjectCreditAmountMapperExt projectCreditAmountMapper;
    @Autowired
    protected PrivacyMasks privacyMasks;
    @Autowired
    protected SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    private static final String LOAN_SUBMIT_LOCK = "loan_submit_lock:";
    public static final int PRECISION_TWO = 2;

    public <C extends LoanConfigResDTO> C getConfig(String userId, Class<C> clazz) {
        LoanConfigResDTO loanConfigResDTO = new LoanConfigResDTO();

        //借款配置类型
        ProjectTypeEnum projectType = getProjectType();

        //初始化借款费率配置数据
        initLoanRateList(loanConfigResDTO,projectType);

        //初始化借款业务信息数据
        initBusinessInfo(userId, loanConfigResDTO,projectType);

        //初始化借款业务配置数据
        initBusinessConfig(loanConfigResDTO,projectType);

        return clazz.cast(loanConfigResDTO);
    }

    public void submit(I req, O res) {
        beforeAfterSubmit(req,res,(i,o)->{
            //借款提交提交检查
            submitCheck(i,o);

            doSumbit(i);
        });
    }

    public void backSubmit(I req, O res) {
        beforeAfterSubmit(req,res,(i,o)->{
            //借款提交提交检查
            backSubmitCheck(i,o);

            doBackSumbit(i);
        });
    }

    /**
     * 审核通过确认后提交借款（用户没有修改金额，提交后直接上标）
     * @param req
     * @param res
     */
    public void auditConfirm(I req, O res) {
        beforeAfterSubmit(req,res,(i,o)->{
            //审核确认检查
            auditConfirmCheck(i,o);

            doAuditConfirm(i);
        });
    }

    /**
     * 重新确认提交检查(提额认证后确认提交借款使用，用户修改了金额：原标的流标+新生成一个标的)
     * @param req
     * @param res
     */
    public void reConfirmSubmit(I req, O res) {
        beforeAfterSubmit(req,res,(i,o)->{
            //重新确认提交检查
            reConfirmSubmitCheck(i,o);

            doReConfirmSubmit(i);
        });
    }

    private void beforeAfterSubmit(I req, O res, BiConsumer<I,O> biConsumer){
        BASubmitDTO baSubmitDTO = obtainBASubmitDTO(req);

        //借款提交前处理（目前只有加锁）
        beforeSubmit(baSubmitDTO);

        try{
            biConsumer.accept(req, res);
        }finally {
            //借款提交后处理（目前只有释放锁）
            afterSubmit(baSubmitDTO);
        }
    }

    protected void beforeSubmit(BASubmitDTO baSubmitDTO){
        String userId = baSubmitDTO.getUserId();
        log.info("借款提交##beforeSubmit##开始userId={}",userId);
        RLock lock = baSubmitDTO.getLock();
        boolean tryLockResult = false;
        try {
            tryLockResult = lock.tryLock(-1, 110000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.error("借款提交##beforeSubmit##异常##userId={}",userId,e);
            throw new RuntimeException("服务器异常，请稍后再试");
        }
        if(!tryLockResult){
            log.info("借款提交##beforeSubmit##锁已被占用##userId={}",userId);
            throw new BizException("TRD90002");
        }
        log.info("借款提交##beforeSubmit##结束userId={}",userId);
    }

    protected void afterSubmit(BASubmitDTO baSubmitDTO){
        String userId = baSubmitDTO.getUserId();
        log.info("借款提交##afterSubmit##开始userId={}",userId);
        RLock lock = baSubmitDTO.getLock();
        Optional.ofNullable(lock).ifPresent(l->l.unlock());
        log.info("借款提交##afterSubmit##结束userId={}",userId);
    }

    protected BASubmitDTO obtainBASubmitDTO(I req){
        String userId = req.getUserId();
        BASubmitDTO baSubmitDTO = new BASubmitDTO();
        final String speedLoanApplyLockKey = LOAN_SUBMIT_LOCK + userId;
        RLock lock = redissonClient.getLock(speedLoanApplyLockKey);
        baSubmitDTO.setUserId(userId);
        baSubmitDTO.setLock(lock);
        return baSubmitDTO;
    }

    //标的子状态检查
    @Transactional(rollbackFor = Exception.class)
    public void projectSubStatusCheck(Long projectId,List<ProjectSubStatusEnum> origSubStatusEnumList){
        Project project = projectMapper.selectByPrimaryKeyForUpdate(projectId);
        Integer subStatus = project.getSubStatus();
        for(ProjectSubStatusEnum origSubStatusEnum:origSubStatusEnumList){
            if(origSubStatusEnum.getSubStatus()==subStatus.intValue()){
                return;
            }
        }
        throw new BizException("TRD1000008");
    }

    protected void initLoanRateList(LoanConfigResDTO loanConfigResDTO,ProjectTypeEnum projectTypeEnum){
        List<ProjectRateConfig> rateConfigList = loanConfigService.selectRateConfigListByTypeEnum(projectTypeEnum);

        if(CollectionUtils.isEmpty(rateConfigList)){
            return;
        }
        List<LoanConfigResDTO.LoanRateConfigDTO> loanRateList = new ArrayList<>();
        for(ProjectRateConfig rateConfig : rateConfigList){
            LoanConfigResDTO.LoanRateConfigDTO loanRateConfigDTO = new LoanConfigResDTO.LoanRateConfigDTO();
            loanRateConfigDTO.setDeadline(rateConfig.getDeadline());
            loanRateConfigDTO.setRepaymentMode(rateConfig.getRepaymentMode());
            BigDecimal borrowInterestRate = rateConfig.getBorrowInterestRate();
            borrowInterestRate = (borrowInterestRate==null?BigDecimal.ZERO:borrowInterestRate);
            loanRateConfigDTO.setBorrowInterestRate(borrowInterestRate.multiply(new BigDecimal("100")));
            loanRateList.add(loanRateConfigDTO);
        }
        loanConfigResDTO.setLoanRateList(loanRateList);
    }

    protected void initBusinessInfo(String userId, LoanConfigResDTO loanConfigResDTO,ProjectTypeEnum projectTypeEnum){
        LoanBusinessInfo loanBusinessInfo = loanConfigService.selectBusinessInfo(projectTypeEnum);
        if(loanBusinessInfo==null){
            return;
        }

        BeanUtils.copyProperties(loanBusinessInfo, loanConfigResDTO);

        loanConfigResDTO.setDeadlineList(getDeadlineList(loanBusinessInfo.getLoanDeadlines()));

        String loanPurposes = loanBusinessInfo.getLoanPurposes();
        loanConfigResDTO.setLoanTitleList(StringUtils.hasText(loanPurposes) ? Arrays.asList(loanPurposes.split( ",")) : null);

        loanConfigResDTO.setAviAmount(getAviAmountRmZero(userId));
    }

    protected void initBusinessConfig(LoanConfigResDTO loanConfigResDTO,ProjectTypeEnum projectTypeEnum){
        LoanBusinessConfig loanBusinessConfig = loanConfigService.selectBusinessConfig(projectTypeEnum);
        if(loanBusinessConfig==null){
            return;
        }
        loanConfigResDTO.setAmountTimes(loanBusinessConfig.getAmountTimes());
    }

    private List<Integer> getDeadlineList(String loanDeadlines){
        if(!StringUtils.hasText(loanDeadlines)){
            return null;
        }
        String[] loanDeadlineArray = loanDeadlines.split(",");
        List<Integer> loanDeadlineList = new ArrayList<>();
        for(String s:loanDeadlineArray){
            Integer deadline = Integer.valueOf(s);
            loanDeadlineList.add(deadline);
        }
        return loanDeadlineList;
    }

    protected void doSumbit(I req){
        Project project = obtainProjectInfoForSubmit(req);

        this.borrowPrizeOccupy(req,project.getProjectId());
        
        //设置借款每日总次数限制
        setLoanQuantityLimit(req);

        //借款标的相关信息创建
        getSelfProxy().loanProjectRelateInfoCreat(req,project);

        doCommonSumbit(req,project);
    }

    protected void doBackSumbit(I req){
        Project project = obtainProjectInfoForBackSubmit(req);

        //退回资料不会重新选择红包
        /*BorrowPrizeOccupyDTO borrowPrizeOccupyDTO = new BorrowPrizeOccupyDTO();
        BeanUtils.copyProperties(req,borrowPrizeOccupyDTO);
        this.borrowPrizeOccupy(borrowPrizeOccupyDTO,project.getProjectId());*/


        //设置借款每日总次数限制
//        setLoanQuantityLimit(req);

        //借款标的相关信息更新
        getSelfProxy().loanProjectRelateInfoUpdate(req,project);

        doCommonSumbit(req,project);
    }

    protected void doCommonSumbit(I req, Project project){
        String userId = project.getBorrowUserId();
        Long projectId = project.getProjectId();

        //签订还款服务委托书合同
        fadadaWithholdContractSign(userId,projectId);

        //变更用户身份标示
        changeUserIdentityTag(userId,project.getLoanTimes());

        //2017邀请好友活动发标事件处理
        inviteBestirActivityProjectPublish(project);

        //标的状态变更事件回流
        projecctStatusChangePush(projectId);

        //发标信用额度变更消息推送
        sendMsgForAviAmountChange(userId);
    }

    private Project obtainProjectInfoForSubmit(I req){
        Date now = new Date();
        Project project = obtainProjectInfo(req);
        project.setCreateTime(now);  //添加时间
        project.setSubmitTime(now);  //借款人提交到后台审核时间
        project.setUpdateTime(now);  //更新时间
        project.setProjectId(snowflakeIdWorker.nextId());
        return project;
    }

    private Project obtainProjectInfoForBackSubmit(I req){
        Date now = new Date();
        Project project = obtainProjectInfo(req);
        project.setSubmitTime(now);  //借款人提交到后台审核时间
        project.setUpdateTime(now);  //更新时间
        LoanBackSubmitReqDTO loanBackSubmitReqDTO = (LoanBackSubmitReqDTO)req;
        project.setProjectId(loanBackSubmitReqDTO.getProjectId());

        //回退标的因为不会修改金额，所以不会回退红包，并且在重新提交借款时不能重新选择红包，所以红包ID要从历史数据中获取
        Project oldProject = projectMapper.selectProjectByUserIdProjectId(req.getUserId(), loanBackSubmitReqDTO.getProjectId());
        project.setPrizeId(oldProject.getPrizeId());

        return project;
    }

    private Project obtainProjectInfoForReConfirm(I req){
        LoanReConfirmSubmitDTO dto = (LoanReConfirmSubmitDTO)req;
        Date now = new Date();
        String userId = dto.getUserId();
        Long projectId = dto.getProjectId();
        Project project = projectMapper.selectProjectByUserIdProjectId(userId,projectId);
        project.setBorrowUserId(userId);
        project.setProjectId(projectId);
        project.setPrizeId(req.getPrizeId());
        project.setTeProjectFlag(TeProjectFlagEnum.YES.getValue());
        project.setSubmitTime(now);  //借款人提交到后台审核时间
        project.setConfirmTime(now);
        project.setUpdateTime(now);  //更新时间
        return project;
    }

    private Project obtainProjectInfo(I req){
        Project project = new Project();
        String userId = req.getUserId();

        project.setLoanTimes(obtainLoanTimes(userId));  //借款成功次数
        project.setTitle(obtainLoanTitle(req)); //项目标题
        project.setContractAmount(req.getLoanAmount()); //合同金额,也即标的金额
        project.setHandAmount(req.getLoanAmount()); //到手金额
        project.setStatus(ProjectSubStatusEnum.CHECKING_INIT.getParentStatusEnum().getStatus());
        project.setSubStatus(ProjectSubStatusEnum.CHECKING_INIT.getSubStatus());
//        project.setChannelCode("app"); //投放渠道
        project.setType(getProjectType().getValue());  //标的类型，参考枚举BorrowProjectTypeEnum
        project.setFromSource(req.getFromSource()); //标的来源（1、APP，2、H5活动，3、H5极速借,4、融360）
        project.setContactsBackflowStatus(ContactsBackflowStatusEnum.NO.getValue());
        project.setCreditType(getLoanSubmitMapEnum().getCreditModelType()); //授信额度类型(0,未知，1:社保,2:芝麻,3:学历,4:融360,5:自有资质,6:融360自有资质,7:信用卡)
        project.setLoanType(ProjectCreditTypeEnum.typeOf(project.getCreditType()).getLoanTypeEnum().getValue());
        project.setLongitude(req.getLongitude()); //经度
        project.setLatitude(req.getLatitude()); //纬度
        project.setLoanProvince(req.getProvince()); //借款省
        project.setLoanCity(req.getCity());  //借款市
        project.setLoanArea(req.getArea());  //借款区
        project.setPrizeId(req.getPrizeId());
        project.setAutoAuditResult(null);
        project.setOrgId(OrgConstant.NIIWOO_ORG_ID);
        project.setBorrowerType(BorrowerTypeEnum.PERSONAL.getType());
        project.setIsMasterBorrower((byte) 1);

        AccountBaseResponse accountBaseResponse = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.BORROWERS);
        project.setBorrowAccountId(accountBaseResponse.getAccountId());
        project.setBorrowPlatformUserNo(accountBaseResponse.getAccountNo());

        //设置用户相关信息
        LoanUserInfoDTO loanUserInfoDTO = obtainLoanUserInfo(userId);
        BeanUtils.copyProperties(loanUserInfoDTO,project);

        //设置费用相关信息
        LoanFeeDTO loanFeeDTO = obtainLoanFeeDTO(req);
        BeanUtils.copyProperties(loanFeeDTO,project);

        // 初次申请金额、期限
        project.setFirstDeadline(project.getDeadline());
        project.setFirstDeadlineUnit(project.getDeadlineUnit());
        project.setFirstAmount(project.getContractAmount());

        return project;
    }

    private String obtainLoanTitle(I req) {
        String loanTitle = req.getLoanTitle();
        if (!StringUtils.hasText(loanTitle)) {
            return "";
        }
        return ProjectInfoUtil.getLoanUsage(loanTitle);
    }

    private int obtainLoanTimes(String userId){
        return projectCommonService.statisticsProjectCountByStatus(userId, Arrays.asList(ProjectStatusEnum.REPAYING.getStatus(), ProjectStatusEnum.FINISH.getStatus()), null);
    }

    private LoanUserInfoDTO obtainLoanUserInfo(String userId){
        LoanUserInfoDTO loanUserInfoDTO = new LoanUserInfoDTO();
        //获取用户基本信息
        UserBasicInfoResponseDTO userBasicInfo = loanQueryService.getUserBasicInfo(userId);
        //获取用户身份证信息
        UserIdentityInfoResponseDTO userIdentityInfo = loanQueryService.getUserIdentityInfo(userId);
        //获取用户授权相关信息
        UserAuthorizationInfoResponseDTO userAuthorizationInfo = loanQueryService.getUserAuthorizationInfo(userId);

        loanUserInfoDTO.setBorrowUserId(userId);
        loanUserInfoDTO.setBorrowUserName(userIdentityInfo.getName()); //借款人姓名
        loanUserInfoDTO.setBorrowMobile(this.ecryptString(userBasicInfo.getMobileNo())); //借款人手机号，加密
        loanUserInfoDTO.setBorrowIdCard(this.ecryptString(userIdentityInfo.getIdCard())); //身份证号，加密
        loanUserInfoDTO.setBorrowNickName(userBasicInfo.getNickName()); //昵称
        loanUserInfoDTO.setBorrowHeadImage(userBasicInfo.getHeadImage()); //头像
        loanUserInfoDTO.setBorrowGender(userBasicInfo.getGender()); //性别
        loanUserInfoDTO.setBorrowNiiwooScore(userBasicInfo.getNiiwooScore()); //你我分
        loanUserInfoDTO.setZhimaScore(userAuthorizationInfo.getZhimaScore()); //芝麻分(冗余)

        return loanUserInfoDTO;
    }

    private LoanFeeDTO obtainLoanFeeDTO(I req){
        LoanFeeDTO loanFeeDTO = new LoanFeeDTO();
        Integer deadline = req.getDeadline();
        BigDecimal loanAmount = req.getLoanAmount();
        ProjectTypeEnum projectTypeEnum = getProjectType();
        LoanBusinessInfo loanBusinessInfo = loanConfigService.selectBusinessInfo(projectTypeEnum);
        ProjectRateConfig projectRateConfig = loanConfigService.selectRateConfigByDeadlineTypeEnum(deadline,projectTypeEnum);

        BigDecimal overDueFee = loanBusinessInfo.getOverDueFee(); //罚息率
        BigDecimal platformManageFeeRate = projectRateConfig.getPlatformManageFeeRate();
        BigDecimal guaranteeServiceFeeRate = projectRateConfig.getGuaranteeServiceFeeRate();

        loanFeeDTO.setDeadline(deadline);
        loanFeeDTO.setDeadlineUnit(DeadlineUnitEnum.BY_MONTH.getDeadlineUnit()); //期数单位(1:月，2:天)
        loanFeeDTO.setPenaltyRate(overDueFee); //罚息率
        loanFeeDTO.setBorrowRate(projectRateConfig.getBorrowInterestRate()); //借款利率
        loanFeeDTO.setManageRate(platformManageFeeRate); //平台管理费率
        loanFeeDTO.setGuaranteeRate(guaranteeServiceFeeRate); //担保费率
        loanFeeDTO.setRepaymentType(projectRateConfig.getRepaymentMode());//还款方式1、到期还本付息，2、等额本息
        loanFeeDTO.setManageFee(loanAmount.multiply(platformManageFeeRate).setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        loanFeeDTO.setGuaranteeFee(loanAmount.multiply(guaranteeServiceFeeRate).setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        return loanFeeDTO;
    }

    //借款红包占用I req
    private void borrowPrizeOccupy(I req, Long projectId){
        Long prizeId = req.getPrizeId();
        if(prizeId==null || prizeId==0){
            return;
        }

        BorrowPrizeOccupyDTO borrowPrizeOccupyDTO = new BorrowPrizeOccupyDTO();
        BeanUtils.copyProperties(req,borrowPrizeOccupyDTO);

        String userId = borrowPrizeOccupyDTO.getUserId();
        log.info("borrowPrizeOccupy.userId={},projectId={},prizeId={} start",userId,projectId,prizeId);

        //红包占用本地日志记录生成
        ProjectBorrowerPrizeOccupyRecord projectBorrowerPrizeOccupyRecord = loanLocalService.buildProjectBorrowerPrizeOccupyRecord(borrowPrizeOccupyDTO, projectId);

        //调用活动接口占用红包
        ActivityPrizeStatusReqDTO prizeRequestDTO = new ActivityPrizeStatusReqDTO();
        prizeRequestDTO.setOrderNo(projectBorrowerPrizeOccupyRecord.getOrderNo());
        prizeRequestDTO.setUserId(userId);
        prizeRequestDTO.setPrizeId(prizeId);
        prizeRequestDTO.setProjectId(projectId);
        prizeRequestDTO.setDeadLine(borrowPrizeOccupyDTO.getDeadline());
        prizeRequestDTO.setAmount(borrowPrizeOccupyDTO.getLoanAmount());
        prizeRequestDTO.setSuitProjectTypeEnum(getPrizeTypeEnum());

        boolean prizeOccupyResult = true;
        try {
            log.info("borrowPrizeOccupy.userId={},projectId={},prizeId={},prizeRequestDTO={}",userId,projectId,prizeId,JSON.toJSONString(prizeRequestDTO));
            prizeOccupyResult = activityPrizeDubboService.setPrizeUsedToOccupied(prizeRequestDTO);
        } catch (Exception e) {
            log.error("borrowPrizeOccupy.userId={},projectId={},prizeId={} error,prizeOccupyResult={}",userId,projectId,prizeId,prizeOccupyResult,e);
            loanLocalService.updateProjectBorrowerPrizeOccupyRecordStatus(projectBorrowerPrizeOccupyRecord,BorrowPrizeOccupyEnum.OccupyStatusEnum.ERROR);
            //出现异常情况下需要退回红包
            this.resetPrizeToReturned(userId,prizeId);
            throw new BizException("TRD10011");
        }
        log.info("borrowPrizeOccupy.userId={},projectId={},prizeId={},prizeOccupyResult={}",userId,projectId,prizeId,prizeOccupyResult);
        if(!prizeOccupyResult){
            log.info("borrowPrizeOccupy.userId={},projectId={},prizeId={},借款提交占用红包失败,prizeOccupyResult={}",userId,projectId,prizeId,prizeOccupyResult);
            loanLocalService.updateProjectBorrowerPrizeOccupyRecordStatus(projectBorrowerPrizeOccupyRecord,BorrowPrizeOccupyEnum.OccupyStatusEnum.FAIL);
            throw new BizException("TRD10011");
        }else{
            loanLocalService.updateProjectBorrowerPrizeOccupyRecordStatus(projectBorrowerPrizeOccupyRecord,BorrowPrizeOccupyEnum.OccupyStatusEnum.SUCCESS);
        }
        log.info("borrowPrizeOccupy.userId={},projectId={},prizeId={} end",userId,projectId,prizeId);
    }

    private UserPrizeSuitProjectTypeEnum getPrizeTypeEnum(){
        LoanSubmitTypeEnum loanSubmitMapEnum = getLoanSubmitMapEnum();
        return UserPrizeSuitProjectTypeEnum.getTypeEnum(loanSubmitMapEnum.getPrizeType());
    }
    
    //设置借款每日总次数限制
    private void setLoanQuantityLimit(I req){
        LoanQuantityConfig loanQuantityConfig = loanConfigService.selectLoanQuantityConfig(getProjectType().getValue(),req.getDeadline());
        if(!this.isNeedCheckForLoanEverydayLoanLimit(req.getDeadline(),loanQuantityConfig)){
            return;
        }

        String loanQuantityLimitKey = getLoanQuantityLimitKeyPrefix() + req.getDeadline().toString() + FastDateFormat.getInstance("yyyyMMdd").format(new Date());
        long loanQuantityLimitCount = redisTemplate.opsForValue().increment(loanQuantityLimitKey,1l);
        log.info("setLoanQuantityLimit.loanQuantityLimitCount={}",loanQuantityLimitCount);
        redisTemplate.expire(loanQuantityLimitKey, this.getLeftSecondsToday(), TimeUnit.SECONDS);
    }

    private String getLoanQuantityLimitKeyPrefix(){
        return LOAN_QUANTITY_LIMIT_KEY+"_"+getProjectType().getValue()+"_";
    }

    /**
     * 获取当天剩余秒数
     */
    private long getLeftSecondsToday() {
        LocalDate now = new LocalDate();
        return new Duration(now.toDateTimeAtCurrentTime(), now.plusDays(1).toDateTimeAtStartOfDay()).getStandardSeconds();
    }

    //红包退回
    private void resetPrizeToReturned(String userId,Long prizeId){
        log.info("resetPrizeToReturned.userId={},prizeId={} start",userId,prizeId);
        try {
            ActivityPrizeResetStatusReqDTO reqDTO = new ActivityPrizeResetStatusReqDTO();
            reqDTO.setUserId(userId);
            reqDTO.setPrizeId(prizeId);
            reqDTO.setOrderNo(snowflakeIdWorker.nextId());
            CompletableFuture.runAsync(() -> activityPrizeDubboService.resetPrizeToReturned(reqDTO));
        } catch (Exception e) {
            log.error("resetPrizeToReturned.userId={},prizeId={} error",userId,prizeId,e);
        }
        log.info("resetPrizeToReturned.userId={},prizeId={} end",userId,prizeId);
    }

    /**
     * 还款服务委托书生成
     * @param userId
     * @param projectId
     * @return
     */
    public FadadaWithholdContractSignResponseDTO fadadaWithholdContractSign(String userId, Long projectId){
        FadadaWithholdContractSignResponseDTO resultDTO = new FadadaWithholdContractSignResponseDTO();
        resultDTO.setSignResult(FadadaWithholdContractSignResponseDTO.FAIL);

        try {
            if(this.isContractSign(userId)){
                log.info("fadadaWithholdContractSign还款服务委托书合同已经生成,userId={}",userId);
                resultDTO.setSignResult(FadadaWithholdContractSignResponseDTO.SUCCESS);
                return resultDTO;
            }

            //先修改签约状态为已经签约
            updateDataStatus(userId, UserDataStatusEnum.WithholdContractSignStatus.ALREADY_SIGN);
            loanLocalService.fadadaWithholdContractSign(userId,projectId);

            resultDTO.setSignResult(FadadaWithholdContractSignResponseDTO.SUCCESS);
        } catch (Exception e) {
            log.error("fadadaWithholdContractSign还款服务委托书合同生成异常,userId={}",userId,e);
        }
        return resultDTO;
    }

    private boolean isContractSign(String userId){
        log.info("isContractSign start userId={}",userId);
        DataStatusResponseDTO withholdContractSignStatus = userStatusDubboService.getByUserIdAndType(userId, UserDataTypeEnum.WITHHOLD_CONTRACT_SIGN);
        log.info("isContractSign.userId={},withholdContractSignStatus={}",userId,JSON.toJSONString(withholdContractSignStatus));
        if(withholdContractSignStatus!=null
                && UserDataStatusEnum.WithholdContractSignStatus.ALREADY_SIGN.getStatus().intValue()==withholdContractSignStatus.getDataStatus().intValue()){
            return true;
        }
        return false;
    }

    private void updateDataStatus(String userId,UserDataStatusEnum.WithholdContractSignStatus dataStatusEnum){
        Date now = new Date();
        DataStatusRequestDTO dataStatusDTO = new DataStatusRequestDTO();
        dataStatusDTO.setUserId(userId);
        dataStatusDTO.setDataType(UserDataTypeEnum.WITHHOLD_CONTRACT_SIGN.getValue());
        dataStatusDTO.setDataStatus(dataStatusEnum.getStatus());
        dataStatusDTO.setAuthTime(now);
        dataStatusDTO.setCreateTime(now);
        userStatusDubboService.saveDataStatusByUserIdAndType(dataStatusDTO);
    }

    private void changeUserIdentityTag(String userId,Integer loanTimes){
        log.info("changeUserIdentityTag userId={},loanTimes={} start",userId,loanTimes);
        if(loanTimes.intValue()>0){
            log.info("changeUserIdentityTag userId={},loanTimes={},首次借款才设置",userId,loanTimes);
            return;
        }
        try {
            CompletableFuture.runAsync(() -> userBasicInfoDubboService.changeUserIdentityTag(userId, UserIdentityEnum.BORROWER));
            log.info("changeUserIdentityTag userId={},loanTimes={} success end",userId,loanTimes);
        } catch (Exception e) {
            log.error("changeUserIdentityTag userId={},loanTimes={} error",userId,loanTimes,e);
        }
    }

    private void inviteBestirActivityProjectPublish(Project project){
        String userId = project.getBorrowUserId();
        log.info("SpeedLoanDubboServiceImpl.inviteBestirActivityProjectPublish.userId={} start",userId);
        try {
            ProjectPublishEventDTO projectPublishEventDTO = new ProjectPublishEventDTO();
            projectPublishEventDTO.setUserId(userId);
            projectPublishEventDTO.setProjectId(project.getProjectId());
            projectPublishEventDTO.setProjectType(com.niiwoo.activity.stage.enums.inviterBuddy.ProjectTypeEnum.findForValue(Integer.valueOf(project.getType())));
            projectPublishEventDTO.setDateTime(project.getCreateTime());
            log.info("SpeedLoanDubboServiceImpl.inviteBestirActivityProjectPublish.userId={},projectPublishEventDTO={}",userId,JSON.toJSONString(projectPublishEventDTO));
            CompletableFuture.runAsync(() -> inviteBuddyActivityDubboService.inviteBestirActivityProjectPublish(projectPublishEventDTO));
            log.info("SpeedLoanDubboServiceImpl.inviteBestirActivityProjectPublish.userId={} end",userId);
        } catch (Exception e) {
            log.info("SpeedLoanDubboServiceImpl.inviteBestirActivityProjectPublish.userId={} error",userId,e);
        }
    }

    private void projecctStatusChangePush(Long projectId){
        //标的状态变更事件回流
        try {
            ProjectStatusChangeBackFlowRequestDTO projectStatusChangeBackFlowRequestDTO = new ProjectStatusChangeBackFlowRequestDTO();
            projectStatusChangeBackFlowRequestDTO.setStatus(String.valueOf(ProjectSubStatusEnum.CHECKING_INIT.getSubStatus()));
            projectStatusChangeBackFlowRequestDTO.setFromStatus(String.valueOf(ProjectSubStatusEnum.CHECKING_INIT.getSubStatus()));
            projectStatusChangeBackFlowRequestDTO.setProjectId(projectId);

            RpcContext.getContext().asyncCall(() -> tianChengDataBackFlowDubboService.projecctStatusChange(projectStatusChangeBackFlowRequestDTO));
        } catch (Exception e) {
            log.error("标的状态变更事件回流(申请中),标的ID={},发生系统异常,原因={}", projectId, e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void loanProjectRelateInfoCreat(I req, Project project) {
        log.info("loanProjectRelateInfoCreat.insertProject={}",JSON.toJSONString(project));
        String userId = req.getUserId();
        Long projectId = project.getProjectId();

        projectMapper.insertSelective(project);

        //插入设备信息
        this.projectLoanDeviceInfoCreat(req,project);

        loanDataBackFlowCreate(userId,projectId,req);

        //插入标的费率数据
        projectRateCreat(userId,projectId,req.getDeadline());

        addProjectDynamicRecord(project);

        initFirstStepProjectFlowExecute(req, project);
    }

    @Transactional(rollbackFor = Exception.class)
    public void loanProjectRelateInfoUpdate(I req, Project project) {
        String userId = req.getUserId();
        Long projectId = project.getProjectId();

        //标的状态检查
        projectSubStatusCheck(projectId,
                Arrays.asList(
                        ProjectSubStatusEnum.CHECKING_BACK,
                        ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT,
                        ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT
                ));

        projectMapper.updateForBackProject(project);

        projectLoanDeviceInfoUpdate(req,project);

        //插入通讯录信息
        loanDataBackFlowCreate(userId,projectId,req);

        //插入标的费率数据
        projectRateCreat(userId,projectId,req.getDeadline());

        addProjectDynamicRecord(project);

        initFirstStepProjectFlowExecute(req, project);
    }

    @Transactional(rollbackFor = Exception.class)
    public void loanProjectRelateInfoUpdateForAuditConfirm(I req, Project project) {
        String userId = req.getUserId();
        Long projectId = project.getProjectId();

        projectSubStatusCheck(projectId,Arrays.asList(ProjectSubStatusEnum.CHECKING_FOR_CONFIRM));

        project.setSubStatus(ProjectSubStatusEnum.CHECKING_FOR_CONFIRMED.getSubStatus());
        projectMapper.updateForBackProject(project);

        //projectLoanDeviceInfoUpdate(req,project,isCreated);

        //插入通讯录信息
        //loanDataBackFlowCreate(userId,projectId,req,isCreated);

        //插入标的费率数据
        projectRateCreat(userId,projectId,req.getDeadline());

        addProjectDynamicRecord(project);

        //更新标的授信额度信息
        updateProjectCreditAmountInfo(project);

        //initFirstStepProjectFlowExecute(req, project,isCreated);
    }

    public void updateProjectCreditAmountInfo(Project project){
        ProjectCreditAmount projectCreditAmount = new ProjectCreditAmount();
        projectCreditAmount.setUserId(project.getBorrowUserId());
        projectCreditAmount.setProjectId(project.getProjectId());
        projectCreditAmount.setLastApplyAmount(project.getHandAmount());
        projectCreditAmount.setUpdateTime(new Date());
        projectCreditAmountMapper.updateByPrimaryKeySelective(projectCreditAmount);
    }

    public void addProjectDynamicRecord(Project project){
        ProjectDynamicDTO projectDynamicDTO = new ProjectDynamicDTO();
        projectDynamicDTO.setUserId(project.getBorrowUserId());
        projectDynamicDTO.setProjectId(project.getProjectId());
        projectDynamicDTO.setTradeTypeEnum(ProjectDynamicDTO.TradeTypeEnum.REPAYMENT);
        projectDynamicDTO.setProjectDynamicEnum(ProjectDynamicEnum.APPLY_SUBMIT_SUCCESS);
        projectLocalService.addProjectDynamicRecord(projectDynamicDTO);
    }

    public void initFirstStepProjectFlowExecute(I req, Project project){
        projectFlowExecuteService.initFirstStepProjectFlowExecute(project.getProjectId(),req.getUserId(), ProjectTypeEnum.getEnum(project.getType()));
    }

    public void initTeAmoutSubmitFirstStepExecute(I req, Project project){
        projectFlowExecuteService.initTeAmoutSubmitFirstStepExecute(project.getProjectId(),req.getUserId(), getProjectType());
    }

    private void loanDataBackFlowCreate(String userId,Long projectId,I req){
        ProjectTypeEnum borrowProjectTypeEnum = getProjectType();

        List<DataBackflowStatusAndDetailsDTO> dataBackflowStatusAndDetailsList = new ArrayList<>();

        DataBackflowStatusAndDetailsDTO baseInfo = new DataBackflowStatusAndDetailsDTO();
        baseInfo.setUserId(userId);
        baseInfo.setProjectId(projectId);
        baseInfo.setProjectTypeEnum(borrowProjectTypeEnum);

        dataBackflowStatusAndDetailsList.add(initDataBackflowStatusAndDetail(baseInfo,DataBackflowStatusDataTypeEnum.IDENTITY_REAL_INFO));
        dataBackflowStatusAndDetailsList.add(initDataBackflowStatusAndDetail(baseInfo,DataBackflowStatusDataTypeEnum.LOAN_INFO));
        dataBackflowStatusAndDetailsList.add(initDataBackflowStatusAndDetail(baseInfo,DataBackflowStatusDataTypeEnum.PERSONAL_INFO));
        dataBackflowStatusAndDetailsList.add(initDataBackflowStatusAndDetail(baseInfo,DataBackflowStatusDataTypeEnum.PROFESSION_INFO));
        dataBackflowStatusAndDetailsList.add(initDataBackflowStatusAndDetail(baseInfo,DataBackflowStatusDataTypeEnum.BANK_INFO));

        DataBackflowStatusAndDetailsDTO addressListDTO = initDataBackflowStatusAndDetail(baseInfo,DataBackflowStatusDataTypeEnum.ADDRESS_LIST);

        dataBackflowStatusAndDetailsList.add(addressListDTO);
        addressListDTO.setContentDetails(JSON.toJSONString(req.getAddressInfoList()));

        dataBackflowStatusService.initDataBackflowStatus(dataBackflowStatusAndDetailsList);
    }

    private void projectLoanDeviceInfoUpdate(I req,Project project){
        LoanSubmitReqDTO.DeviceInfoRequestDTO deviceInfoRequestDTO = req.getDeviceInfo();
        ProjectLoanDeviceInfo deviceInfo = new ProjectLoanDeviceInfo();
        BeanUtils.copyProperties(deviceInfoRequestDTO, deviceInfo);
        deviceInfo.setUserId(project.getBorrowUserId());
        deviceInfo.setProjectId(project.getProjectId());
        deviceInfo.setUpdateTime(project.getUpdateTime());
        projectLoanDeviceInfoMapper.updateByUserIdAndProjectSelective(deviceInfo);
    }

    private void projectRateCreat(String userId,Long projectId,Integer deadline){
        //先删除，后插入
        projectRateMapper.deleteByUserIdProjectId(userId,projectId);
        ProjectRateConfig projectRateConfig = loanConfigService.selectRateConfigByDeadlineTypeEnum(deadline,getProjectType());
        List<RateConfigPercent> rateConfigPercentList = loanConfigService.queryConfigPercentByRateConfigId(projectRateConfig.getId());
        for(RateConfigPercent rateConfigPercent:rateConfigPercentList){
            ProjectRate projectRate = new ProjectRate();
            BeanUtils.copyProperties(rateConfigPercent,projectRate);
            projectRate.setId(snowflakeIdWorker.nextId());
            projectRate.setBorrowUserId(userId);
            projectRate.setProjectId(projectId);
            projectRate.setCreateTime(new Date());
            projectRateMapper.insertSelective(projectRate);
        }
    }

    private DataBackflowStatusAndDetailsDTO initDataBackflowStatusAndDetail(DataBackflowStatusAndDetailsDTO baseInfo,DataBackflowStatusDataTypeEnum dataBackflowStatusDataTypeEnum){
        DataBackflowStatusAndDetailsDTO dataBackflowStatusAndDetailsDTO = new DataBackflowStatusAndDetailsDTO();
        BeanUtils.copyProperties(baseInfo,dataBackflowStatusAndDetailsDTO);
        dataBackflowStatusAndDetailsDTO.setDataTypeEnum(dataBackflowStatusDataTypeEnum);
        return dataBackflowStatusAndDetailsDTO;
    }

    public void projectLoanDeviceInfoCreat(I req, Project project){
        LoanSubmitReqDTO.DeviceInfoRequestDTO deviceInfoRequestDTO = req.getDeviceInfo();
        ProjectLoanDeviceInfo deviceInfo = new ProjectLoanDeviceInfo();
        BeanUtils.copyProperties(deviceInfoRequestDTO, deviceInfo);
        deviceInfo.setUserId(project.getBorrowUserId());
        deviceInfo.setProjectId(project.getProjectId());
        deviceInfo.setCreateTime(project.getCreateTime());
        deviceInfo.setUpdateTime(project.getUpdateTime());
        projectLoanDeviceInfoMapper.insertSelective(deviceInfo);
    }

    private boolean isNeedCheckForLoanEverydayLoanLimit(int deadline,LoanQuantityConfig loanBusinessConfig){
        if(loanBusinessConfig==null){
            return false;
        }
        Integer minDeadline = loanBusinessConfig.getMinDeadline();
        Integer maxDeadline = loanBusinessConfig.getMaxDeadline();
        Integer singleDayLoans = loanBusinessConfig.getSingleDayLoans();

        if(minDeadline==null || maxDeadline==null || singleDayLoans==null){
            return false;
        }
        if(minDeadline>deadline || maxDeadline<deadline){
            return false; //借款期限不在限制期限范围，则不做处理
        }
        return true;
    }

    private Project obtainProjectInfoForAuditConfirm(I req){
        LoanAuditConfirmDTO loanAuditConfirmDTO = (LoanAuditConfirmDTO)req;
        String userId = loanAuditConfirmDTO.getUserId();
        Long projectId = loanAuditConfirmDTO.getProjectId();
        
        AuditAdditionalInfo auditAdditionalInfo = auditAdditionalInfoMapper.selectByProjectId(projectId);
		// 防止接口串改
        if (auditAdditionalInfo != null) {
        	// 人工审核-待确认
            if (req.getLoanAmount().compareTo(auditAdditionalInfo.getAuditAmount()) != 0) {
            	req.setLoanAmount(auditAdditionalInfo.getAuditAmount());
            	req.setDeadline(Integer.valueOf(auditAdditionalInfo.getAuditDeadline()));
            }
        } else {
            // 自动审核通过-待确认，非人工后台审核通过 查询额度评分卡
        	BigDecimal loanAmount = Optional.ofNullable(projectCreditAmountMapper.selectByPrimaryKey(projectId)).map(ProjectCreditAmount::getCreditAmount).orElse(BigDecimal.ZERO);
        	
        	if (req.getLoanAmount().compareTo(loanAmount) != 0) {
            	req.setLoanAmount(loanAmount);
            	Project oldProject = projectMapper.selectByPrimaryKey(projectId);
            	req.setDeadline(oldProject.getDeadline());
            }
        }

        Project project = new Project();
        project.setBorrowUserId(userId);
        project.setProjectId(projectId);

        project.setContractAmount(req.getLoanAmount()); //合同金额,也即标的金额
        project.setHandAmount(req.getLoanAmount()); //到手金额
        project.setPrizeId(req.getPrizeId());

        //设置费用相关信息
        LoanFeeDTO loanFeeDTO = obtainLoanFeeDTO(req);
        BeanUtils.copyProperties(loanFeeDTO,project);
        project.setUpdateTime(new Date());  //更新时间

        return project;
    }

    protected void doAuditConfirm(I req){
        Project project = obtainProjectInfoForAuditConfirm(req);

        this.borrowPrizeOccupy(req,project.getProjectId());

        //设置借款每日总次数限制
        //setLoanQuantityLimit(req);

        //借款标的相关信息更新
        getSelfProxy().loanProjectRelateInfoUpdateForAuditConfirm(req,project);

        //doCommonSumbit(req,project);

        //上标
        pushProject(req);

        //标的状态变更事件回流
        projecctStatusChangePush(project.getProjectId());
    }

    protected void doReConfirmSubmit(I req){
        Project project = obtainProjectInfoForReConfirm(req);

        this.borrowPrizeOccupy(req,project.getProjectId());

        //设置借款每日总次数限制
        //setLoanQuantityLimit(req);

        //借款标的相关信息创建
        getSelfProxy().reConfirmSubmitRelateInfoProcess(req,project);

        doCommonSumbit(req,project);
    }

    @Transactional(rollbackFor = Exception.class)
    public void reConfirmSubmitRelateInfoProcess(I req, Project project){
        LoanReConfirmSubmitDTO reqDTO = (LoanReConfirmSubmitDTO)req;
        Long projectId = reqDTO.getProjectId(); //原标的ID

        //原标的状态检查
        projectSubStatusCheck(projectId,Arrays.asList(ProjectSubStatusEnum.CHECKING_FOR_CONFIRM));

        project.setSubStatus(ProjectSubStatusEnum.CHECKING_FOR_CONFIRMED.getSubStatus());
        // 处理前端传入0的非法值
        if(null != project.getPrizeId() && 0 == project.getPrizeId()){
            project.setPrizeId(null);
        }
        projectMapper.updateByPrimaryKeySelective(project);

        //loanProjectRelateInfoCreat(req, project);

        //projectFlow(origProjectId);

        initTeAmoutSubmitFirstStepExecute(req, project);
    }

    @Transactional(rollbackFor = Exception.class)
    public void projectFlow(Long projectId){
        ProjectFlowRequestDTO requestDTO = new ProjectFlowRequestDTO();
        requestDTO.setProjectId(projectId);
        //TODO:wukeTODO
        requestDTO.setSubStatus(ProjectSubStatusEnum.MISCARRY_CANCER_BORROWER);
        requestDTO.setRemark("提额认证重新确认借款流标");
        projectLocalService.flow(requestDTO);
    }

    public void pushProject(I req){
        LoanAuditConfirmDTO loanAuditConfirmDTO = (LoanAuditConfirmDTO)req;
//
//        PushProjectRequestDTO pushProjectRequestDTO = new PushProjectRequestDTO();
//        pushProjectRequestDTO.setProjectId(loanAuditConfirmDTO.getProjectId());
//        pushProjectRequestDTO.setPushFromEnum(PushProjectRequestDTO.PushFromEnum.AUTO_AUDIT);
//        pushProjectRequestDTO.setAuditedTime(new Date());
//        //standardSpeedLoanServiceImpl.pushProject(pushProjectRequestDTO);
//
//        Project project = new Project();
//        project.setType(getProjectType().getValue());
//        project.setFromSource(req.getFromSource());
//        ISpeedLoanService service = iSpeedLoanFactory.adaptive(project);
//        service.pushProject(pushProjectRequestDTO);

        ProjectWaitPublishReqDTO projectWaitPublishReqDTO=new ProjectWaitPublishReqDTO ();
        projectWaitPublishReqDTO.setProjectId(loanAuditConfirmDTO.getProjectId());
        projectWaitPublishReqDTO.setPushFromEnum(ProjectWaitPublishReqDTO.PushFromEnum.AUTO_AUDIT);
        projectWaitPublishReqDTO.setAuditTime(new Date());

        //标的进入待发布列表
        rabbitTemplate.convertAndSend(MqConstant.PROJECT_WAIT_PUBLISH_EXCHANGE, MqConstant.PROJECT_WAIT_PUBLISH_ROUTING, projectWaitPublishReqDTO);
    }

    /**
     * 发标信用额度变更消息推送
     *
     * @param userId
     */
    private void sendMsgForAviAmountChange(String userId) {
        log.info("sendMsgForAviAmountChange:" + userId);
        try {
            activityEventService.sendMsgForAviAmountChange(userId, UsableCreditChangeTypeEventEnum.APPLY);
        } catch (Exception e) {
            log.error("sendMsgForAviAmountChange:" + userId, e);
        }
    }

    //加密字符串
    private String ecryptString(String str) {
        return Optional.ofNullable(str).map(s->{
            return privacyMasks.encryptPrivacy(str);
        }).orElse(null);
    }

    @Getter
    @Setter
    public static class BASubmitDTO {
        private String userId;
        private RLock lock;
    }

    @Data
    public static class LoanFeeDTO{
        private Integer deadline;
        private Byte deadlineUnit;
        private Byte repaymentType; //还款方式1、到期还本付息，2、等额本息
        private BigDecimal penaltyRate; //罚息率每天
        private BigDecimal borrowRate; //借款利率
        private BigDecimal manageRate;  //平台管理费率
        private BigDecimal guaranteeRate; //担保费率
        private BigDecimal manageFee;  //平台管理费费用
        private BigDecimal guaranteeFee; //担保费费用
    }

    @Data
    public static class LoanUserInfoDTO{
        private String borrowUserId;
        private String borrowUserName;
        private String borrowMobile;
        private String borrowIdCard;
        private String borrowHeadImage;
        private String borrowNickName;
        private Byte borrowGender;
        private Integer borrowNiiwooScore;
        private Integer zhimaScore;
    }

    protected AbstractLoanSubmitService getSelfProxy(){
        return (AbstractLoanSubmitService)AopContext.currentProxy();
    }
}
